package com.wangjw.task;

import com.wangjw.common.Const;
import com.wangjw.redis.RedisShardedPoolUtil;
import com.wangjw.util.PropertiesUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

/**
 * Created by wangjw on 18/6/5.
 */
@Component
@Slf4j
public class TaskSample {

//    @Scheduled(cron = "0 */30 * * * ?") // 每30分钟执行一次
    public void timing1() {
        log.info("定时任务启动");
        long lockTimeout = Long.parseLong(PropertiesUtil.getProperty("lock.timeout", "5000"));
        Long setnxResult = RedisShardedPoolUtil.setnx(Const.RedisLock.TASK_LOCK, String.valueOf(System.currentTimeMillis() + lockTimeout));
        if (setnxResult != null && setnxResult.intValue() == 1) {
            // 如果返回值是1，代表设置成功，获得锁
            doTask();
        } else {
            log.info("没有获得分布式锁:{}", Const.RedisLock.TASK_LOCK);
        }
        log.info("定时任务关闭");
    }

    @Scheduled(cron = "0 */30 * * * ?") // 每30分钟执行一次
    public void timing2() { // 防死锁
        log.info("定时任务启动");
        long lockTimeout = Long.parseLong(PropertiesUtil.getProperty("lock.timeout", "5000"));
        Long setnxResult = RedisShardedPoolUtil.setnx(Const.RedisLock.TASK_LOCK, String.valueOf(System.currentTimeMillis() + lockTimeout));
        if (setnxResult != null && setnxResult.intValue() == 1) {
            // 如果返回值是1，代表设置成功，获得锁
            doTask();
        } else {
            // 未获取到锁，继续判断，判断时间戳，看是否可以重置并获取到锁
            String lockValueStr = RedisShardedPoolUtil.get(Const.RedisLock.TASK_LOCK);
            if (lockValueStr != null && System.currentTimeMillis() > Long.parseLong(lockValueStr)) {
                String getSetResult = RedisShardedPoolUtil.getSet(Const.RedisLock.TASK_LOCK, String.valueOf(System.currentTimeMillis() + lockTimeout));
                // 再次用当前时间戳getSet， 返回给定的key的旧值，->旧值判断，是否可以获取锁
                // 当key没有旧值时，即key不存在时，返回nil，->获取锁
                // 这里我们set了一个新的value值，获取旧的值
                if (getSetResult == null || StringUtils.equals(lockValueStr, getSetResult)) {
                    // 真正获取到锁
                    doTask();
                } else {
                    log.info("没有获得分布式锁:{}", Const.RedisLock.TASK_LOCK);
                }
            } else {
                log.info("没有获得分布式锁:{}", Const.RedisLock.TASK_LOCK);
            }
        }
        log.info("定时任务关闭");
    }

    private void doTask() {
        RedisShardedPoolUtil.expire(Const.RedisLock.TASK_LOCK, 5); // 有效期5秒，防止死锁
        log.info("获取{},ThreadName:{}", Const.RedisLock.TASK_LOCK, Thread.currentThread().getName());
        // 业务逻辑省略
        RedisShardedPoolUtil.del(Const.RedisLock.TASK_LOCK);
        log.info("释放{},ThreadName:{}", Const.RedisLock.TASK_LOCK, Thread.currentThread().getName());
    }
}
